#pragma once
#include<stdlib.h>
#include<stdint.h>
#include<string.h>
#include<memory.h>

typedef struct
{
	FILE* filename;
	int file_length;
}FileContent;


//about file operation
FileContent openfile(const char* filename, const char* mode);

//about bit operation
void byte2bit(uint8_t* bch, uint8_t* ch, long bytes_len);
void bit2byte(uint8_t* ch, uint8_t* bch, long bytes_len);

//about statistics
int floor(double num);
int ceil(double num);

//about solving equations
void printMatrix(uint8_t* array, int row, int col);
void swaprow(int col, uint8_t* array, int a, int b);
void addrow(int col, uint8_t* array, int a, int b);
void gaussian_elimination(uint8_t* array, int row, int col);

FileContent openfile(const char* filename, const char* mode)
{
	FILE* File = NULL;
	fopen_s(&File, filename, mode);
	if (File == NULL)
	{
		printf("Cannot open file<%s>!\n",filename);
		return {0,0};
	}
	else
	{
		fseek(File, 0, SEEK_END);
		long len = ftell(File);
		fseek(File, 0, SEEK_SET);
		if(mode != "wb")
		printf("File<%s> length: %ld Bytes.\n",filename,len);
		FileContent result = {File, len};
		return result;
	}
}



void byte2bit(uint8_t* bch, uint8_t* ch, long bytes_len) 
{
	for (int i = 0; i < bytes_len * 8; i=i+8)
	{
		bch[i + 0] = (ch[i / 8] & 0x80) >> 7;
		bch[i + 1] = (ch[i / 8] & 0x40) >> 6;
		bch[i + 2] = (ch[i / 8] & 0x20) >> 5;
		bch[i + 3] = (ch[i / 8] & 0x10) >> 4;
		bch[i + 4] = (ch[i / 8] & 0x08) >> 3;
		bch[i + 5] = (ch[i / 8] & 0x04) >> 2;
		bch[i + 6] = (ch[i / 8] & 0x02) >> 1;
		bch[i + 7] = (ch[i / 8] & 0x01) >> 0;
	}
}
void bit2byte(uint8_t* ch, uint8_t* bch, long bytes_len) 
{
	for (int i = 0; i < bytes_len; i++)
	{
		ch[i] = (bch[8 * i + 0] << 7) | (bch[8 * i + 1] << 6) |
			(bch[8 * i + 2] << 5) | (bch[8 * i + 3] << 4) |
			(bch[8 * i + 4] << 3) | (bch[8 * i + 5] << 2) |
			(bch[8 * i + 6] << 1) | (bch[8 * i + 7] << 0);
	}
}

int floor(double num)
{
	int intPart = (int)num;
	if (num < 0 && num != intPart)
	{
		intPart--;
	}
	return intPart;
}
int ceil(double num)
{
	int intPart = (int)num;
	if (num > intPart)
	{
		return intPart + 1;
	}
	else 
	{
		return intPart;
	}
}

void printMatrix(uint8_t* array, int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d", array[i * col + j]);
		}
		printf("\n");
	}printf("\n");
}
void swaprow(int col, uint8_t* array, int a, int b)
{
	int temp;
	for (int j = 0; j < col; ++j) {
		temp = array[a * col + j];
		array[a * col + j] = array[b * col + j];
		array[b * col + j] = temp;
	}
}
void addrow(int col, uint8_t* array, int a, int b)
{   //row b = row a +row b;
	for (int i = a; i < col; ++i) {
		array[b * col + i] = array[a * col + i] ^ array[b * col + i];
	}
}
void gaussian_elimination(uint8_t* array, int row, int col)
{
	int i, j, k;
	i = 0;
	for (j = 0; j < col; ++j) {
		if (array[i * col + j] == 1) {
		label:
			for (k = i + 1; k < row; ++k) {
				if (array[k * col + j] == 1) {
					addrow(col, array, i, k);
				}
			}
			i++;
		}
		else {
			for (k = i + 1; k < row; ++k) {
				if (array[k * col + j] == 1) {
					swaprow(col, array, k, i);
					goto label;
				}
			}
		}
	}
	/*Has been turned into a line ladder type*/
	for (j = col - 2; j > 0; --j) {
		for (i = j; i > 0; --i) {
			if (array[i * col + j] == 1) {
				for (k = i - 1; k >= 0; --k) {
					if (array[k * col + j] == 1) {
						addrow(col, array, i, k);
					}
				}
			}
		}
	}
	/*Has been made the simplest shape*/
}